package com.base.cn.platform.os.common.utils;

/**
 * @author 96kr-yuanye
 * @create 2019-04-17 11:43
 * @desc
 **/
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import com.base.cn.platform.os.common.md5.MD5;
import lombok.extern.slf4j.Slf4j;

/**
 * CC接口获取参数 THQS 算法
 */
@Slf4j
public class CcLiveUtils{

    public static Map<String, String> createQueryMap(String queryString)
    {
        Map<String, String> map = new HashMap();
        String[] pairs = queryString.split("&");
        try
        {
            String[] arrayOfString1;
            int j = (arrayOfString1 = pairs).length;
            for (int i = 0; i < j; i++)
            {
                String pair = arrayOfString1[i];
                String[] kv = pair.split("=");
                String v;
                String k;
                if (kv.length == 2)
                {
                    k = kv[0];
                    v = kv[1];
                }
                else
                {
                    int pos = pair.indexOf("=");
                    if (pos == -1) {
                        continue;
                    }
                    k = pair.substring(0, pos);
                    v = pair.substring(pos + 1, pair.length());
                }
                String value = "__wrong__";
                try
                {
                    value = URLDecoder.decode(v, "utf-8");
                }
                catch (IllegalArgumentException e)
                {
                    log.error("decode error: " + v);
                }
                map.put(k, value);
            }
        }
        catch (UnsupportedEncodingException e)
        {
            log.error(queryString, e);
            return null;
        }
        return map;
    }

    public static String createQueryString(Map<String, String> queryMap)
    {
        if (queryMap == null) {
            return null;
        }
        if (queryMap.size() == 0) {
            return "";
        }
        try
        {
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : queryMap.entrySet()) {
                if (entry.getValue() != null)
                {
                    String key = ((String)entry.getKey()).trim();
                    String value = URLEncoder.encode((String)entry.getValue(), "utf-8");
                    sb.append(String.format("%s=%s&", new Object[] { key, value }));
                }
            }
            return sb.substring(0, sb.length() - 1);
        }
        catch (StringIndexOutOfBoundsException e)
        {
            log.error("", e);
            return null;
        }
        catch (UnsupportedEncodingException e)
        {
            log.error("", e);
        }
        return null;
    }

    public static String createHashedQueryString(Map<String, String> queryMap, long time, String salt)
    {
        Map<String, String> map = new TreeMap(queryMap);
        String qs = createQueryString(map);
        if (qs == null) {
            return null;
        }
        String htqs;
        if (!qs.equals(""))
        {
            String hash = MD5.getMD5(String.format("%s&time=%d&salt=%s", new Object[] { qs, Long.valueOf(time), salt }));
            htqs = String.format("%s&time=%d&hash=%s", new Object[] { qs, Long.valueOf(time), hash });
        }
        else
        {
            String hash = MD5.getMD5(String.format("time=%d&salt=%s", new Object[] { Long.valueOf(time), salt }));
            htqs = String.format("time=%d&hash=%s", new Object[] { Long.valueOf(time), hash });
        }
        return htqs;
    }
    public static String createHashedQueryString(Map<String, String> queryMap, String salt)
    {
        long time = System.currentTimeMillis()/1000;
        Map<String, String> map = new TreeMap(queryMap);
        String qs = createQueryString(map);
        if (qs == null) {
            return null;
        }
        String htqs;
        if (!qs.equals(""))
        {
            String hash = MD5.getMD5(String.format("%s&time=%d&salt=%s", new Object[] { qs, Long.valueOf(time), salt }));
            htqs = String.format("%s&time=%d&hash=%s", new Object[] { qs, Long.valueOf(time), hash });
        }
        else
        {
            String hash = MD5.getMD5(String.format("time=%d&salt=%s", new Object[] { Long.valueOf(time), salt }));
            htqs = String.format("time=%d&hash=%s", new Object[] { Long.valueOf(time), hash });
        }
        log.info(htqs);
        return htqs;
    }
    public static String createHashedQueryStringBySpace(Map<String, String> queryMap, long time, String salt)
    {
        if (queryMap == null) {
            return null;
        }
        try
        {
            String qs = "";
            if (queryMap.size() != 0)
            {
                StringBuilder sb = new StringBuilder();
                Map<String, String> map = new TreeMap(queryMap);
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    if (entry.getValue() != null)
                    {
                        String key = ((String)entry.getKey()).trim();
                        String value = URLEncoder.encode((String)entry.getValue(), "utf-8");
                        if (value.contains("+")) {
                            value = value.replace("+", "%20");
                        }
                        sb.append(String.format("%s=%s&", new Object[] { key, value }));
                    }
                }
                qs = sb.substring(0, sb.length() - 1);
            }
            String htqs;
            String hash;
            if (!qs.equals(""))
            {
                hash = MD5.getMD5(String.format("%s&time=%d&salt=%s", new Object[] { qs, Long.valueOf(time), salt }));
                htqs = String.format("%s&time=%d&hash=%s", new Object[] { qs, Long.valueOf(time), hash });
            }
            else
            {
                hash = MD5.getMD5(String.format("time=%d&salt=%s", new Object[] { Long.valueOf(time), salt }));
            }
            return String.format("time=%d&hash=%s", new Object[] { Long.valueOf(time), hash });
        }
        catch (StringIndexOutOfBoundsException e)
        {
            log.error("", e);
            return null;
        }
        catch (UnsupportedEncodingException e)
        {
            log.error("", e);
        }
        return null;
    }

    public static boolean validateHashedQueryString(String queryString, String salt, long timeTolerate)
    {
        Map<String, String> map = createQueryMap(queryString);

        return validateHashedQueryMap(map, salt, timeTolerate);
    }

    public static boolean validateHashedQueryMap(Map<String, String> queryMap, String salt, long timeTolerate)
    {
        try
        {
            String hash = (String)queryMap.remove("hash");
            Long time = Long.valueOf(Long.parseLong((String)queryMap.remove("time")));
            Long compatibleTime = time;
            if (compatibleTime.longValue() > 1212345678000L) {
                compatibleTime = Long.valueOf(compatibleTime.longValue() / 1000L);
            }
            Long curTime =System.currentTimeMillis()/1000;
            if (Math.abs(curTime.longValue() - compatibleTime.longValue()) > timeTolerate)
            {
                log.error("Time expired.");
                return false;
            }
            String sqs = createHashedQueryString(queryMap, time.longValue(), salt);
            Map<String, String> gmap = createQueryMap(sqs);
            String ghash = (String)gmap.get("hash");
            if (!ghash.equalsIgnoreCase(hash))
            {
                sqs = createHashedQueryStringBySpace(queryMap, time.longValue(), salt);
                Map<String, String> spaceMap = createQueryMap(sqs);
                String spaceHash = (String)spaceMap.get("hash");
                if (spaceHash.equalsIgnoreCase(hash)) {
                    return true;
                }
                return false;
            }
            return true;
        }
        catch (NumberFormatException e)
        {
            log.error("", e);
        }
        catch (NullPointerException e)
        {
            log.error("", e);
        }
        return false;
    }
}
